////////////////////////////////////////////////////////////////////////////
// Portions Copyright (c) 2012 Kentaro Sekimoto  All rights reserved.
////////////////////////////////////////////////////////////////////////////

#ifndef FM3_USB_FUNCTIONS_H_
#define FM3_USB_FUNCTIONS_H_

#include <tinyhal.h>
#include <pal\com\usb\USB.h>

//#define USB_DEBUG
#ifdef USB_DEBUG
#define USB_DEBUG_INIT
#define USB_DEBUG1(p0)              USB_debug_printf(p0)
#define USB_DEBUG2(p0, p1)          USB_debug_printf(p0, p1)
#define USB_DEBUG3(p0, p1, p2)      USB_debug_printf(p0, p1, p2)
#define USB_DEBUG4(p0, p1, p2, p3)  USB_debug_printf(p0, p1, p2, p3)
#else
#define USB_DEBUG_INIT()
#define USB_DEBUG1(p0)
#define USB_DEBUG2(p0, p1)
#define USB_DEBUG3(p0, p1, p2)
#define USB_DEBUG4(p0, p1, p2, p3)
#endif

#define UPCR2_UPOWT_INIT_VALUE  (0x07)  /* initial value of UPCR2 register's UPOWT bits    */
#define UPCR3_UPLLK_INIT_VALUE  (0x00)  /* initial value of UPCR3 register's UPLLK bits    */
#ifdef MB9BF618T
#ifdef CLK_16M
#define UPCR4_UPLLN_INIT_VALUE  (0x0E)  /* initial value of UPCR4 register's UPLLN bits    */
#define UPCR5_UPLLN_INIT_VALUE  (0x04)  /* initial value of UPCR4 register's UPLLM bits    */
#else
#define UPCR4_UPLLN_INIT_VALUE  (0x3B)  /* initial value of UPCR4 register's UPLLN bits    */
#define UPCR5_UPLLN_INIT_VALUE  (0x04)  /* initial value of UPCR4 register's UPLLM bits    */
#endif
#endif
#ifdef MB9BF506N
#ifdef CLK_16M
#define UPCR4_UPLLN_INIT_VALUE  (0x05)  /* initial value of UPCR4 register's UPLLN bits    */
#else
#define UPCR4_UPLLN_INIT_VALUE  (0x17)  /* initial value of UPCR4 register's UPLLN bits    */
#endif
#endif

#define CONDITION_PID       (0)         /* select alternating data toggle mode */
#define NO_CONDITION_PID    (1)         /* select data toggle mode */
#define BUS_POWER           (1)         /* bus-power */
#define SELF_POWER          (0)         /* self-power */
#define HARD_AUTO_CLEAR     (1)         /* STALL is cleared automatically by hardware */
#define CONDITION_PID       (0)         /* select alternating data toggle mode */
#define NO_CONDITION_PID    (1)         /* select data toggle mode */
#define BUS_POWER           (1)         /* bus-power */
#define SELF_POWER          (0)         /* self-power */
#define HARD_AUTO_CLEAR     (1)         /* STALL is cleared automatically by hardware */

#define USB_EP_TX_DIS       0
#define USB_EP_TX_STALL     1
#define USB_EP_TX_NAK       2
#define USB_EP_TX_VALID     3
#define USB_EP_RX_DIS       0
#define USB_EP_RX_STALL     1
#define USB_EP_RX_NAK       2
#define USB_EP_RX_VALID     3

//#define USBF_INTERRUPT_LEVEL       (12)
#define USBF_INTERRUPT_LEVEL        (12)
#define USB_MAX_EP        6
#define MAX_EP0_SIZE    8
#define USB_MAX_DATA_PACKET_SIZE    64

/* endpoint0 interrupt type */
#define CTRLTRANS_SETUP_DETECTED    (0)     /* setup stage detection    */
#define CTRLTRANS_DATA_RECEIVED     (1)     /* data receiving           */
#define CTRLTRANS_DATA_SENDED       (2)     /* data sending             */

// UDCS -
#define UDCS_SUSP           0x20
#define UDCS_SOF            0x10
#define UDCS_BRST           0x08
#define UDCS_WKUP           0x04
#define UDCS_SETUP          0x02
#define UDCS_CONF           0x01
// EPnC
#define EPNC_EPEN           0x8000
#define EPNC_TYPE_INTERRUPT 0x6000
#define EPNC_TYPE_BULK      0x4000
#define EPNC_TYPE_ISO       0x2000
#define EPNC_TYPE_MASK      0x6000
#define EPNC_DIR            0x1000
#define EPNC_DMAE           0x0800
#define EPNC_NULE           0x0400
#define EPNC_STAL           0x0200
// EP0IS - EP0I Status
#define EP0IS_BFINI         0x8000
#define EP0IS_DRQIIE        0x4000
#define EP0IS_DRQI          0x0400
// EP0OS - EP0O Status
#define EP0OS_BFINI         0x8000
#define EP0OS_DRQOIE        0x4000
#define EP0OS_SPKIE         0x2000
#define EP0OS_DRQO          0x0400
#define EP0OS_SPK           0x0200
#define EP1S_DRQIE          0x4000
#define EP1S_SPKIE          0x2000
#define EP2S_DRQIE          0x4000
#define EP2S_SPKIE          0x2000
#define EP3S_DRQIE          0x4000
#define EP3S_SPKIE          0x2000
#define EP4S_DRQIE          0x4000
#define EP4S_SPKIE          0x2000
#define EP5S_DRQIE          0x4000
#define EP5S_SPKIE          0x2000
// EPNS
#define EPNS_DRQIE          0x4000
#define EPNS_SPKIE          0x2000
#define EPNS_DRQ            0x0400
#define EPNS_SPK            0x0200

#define FM3_USB0_EP0C_ADDR      0x40042124
#define FM3_USB0_EP0IS_ADDR     0x40042144
#define FM3_USB0_EP0OS_ADDR     0x40042148
#define FM3_USB0_EP0DTL_ADDR    0x40042160
#define FM3_USB0_EP0DTH_ADDR    0x40042161

// Macro
#define FM3_USB_Pullup_Connect()        REG_W(bFM3_GPIO_PDOR6_P1, 0)
#define FM3_USB_Pullup_Disconnect()     REG_W(bFM3_GPIO_PDOR6_P1, 1)
#define FM3_USB0_Function_Start()       REG_W(bFM3_USB0_UDCC_RST, 0)
#define FM3_USB0_Function_Reset()       REG_W(bFM3_USB0_UDCC_RST, 1)
#define FM3_USB0_HostConnect()          REG_W(bFM3_USB0_UDCC_HCONX, 0)
#define FM3_USB0_HostDisconnect()       REG_W(bFM3_USB0_UDCC_HCONX, 1)
#define FM3_USB0_BusPower()             REG_W(bFM3_USB0_UDCC_PWC, 0)
#define FM3_USB0_SelfPower()            REG_W(bFM3_USB0_UDCC_PWC, 1)
#define FM3_USB0_RateFeedbackMode()     REG_W(bFM3_USB0_UDCC_RFBK, NO_CONDITION_PID)
#define FM3_USB0_StallClearEnable()     REG_W(bFM3_USB0_UDCC_STALCLREN, HARD_AUTO_CLEAR)
#define FM3_USB0_StallClearDisable()    REG_W(bFM3_USB0_UDCC_STALCLREN, ~HARD_AUTO_CLEAR)
#define FM3_USB0_BusReset_Disable()     REG_W(bFM3_USB0_UDCIE_BRSTIE, 0)
#define FM3_USB0_BusReset_Enable()      REG_W(bFM3_USB0_UDCIE_BRSTIE, 1)
#define FM3_USB0_BusReset_Clear()       REG_W(bFM3_USB0_UDCS_BRST, 0)
#define FM3_USB0_BusReset_Set()         REG_W(bFM3_USB0_UDCS_BRST, 1)
#define FM3_USB0_Suspend_Disable()      REG_W(bFM3_USB0_UDCIE_SUSPIE, 0)
#define FM3_USB0_Suspend_Enable()       REG_W(bFM3_USB0_UDCIE_SUSPIE, 1)
#define FM3_USB0_Suspend_Clear()        REG_W(bFM3_USB0_UDCS_SUSP, 0)
#define FM3_USB0_Suspend_Set()          REG_W(bFM3_USB0_UDCS_SUSP, 1)
#define FM3_USB0_Resume_Clear()         REG_W(bFM3_USB0_UDCC_RESUM, 0)
#define FM3_USB0_Resume_Set()           REG_W(bFM3_USB0_UDCC_RESUM, 1)
#define FM3_USB0_Wakeup_Disable()       REG_W(bFM3_USB0_UDCIE_WKUPIE, 0)
#define FM3_USB0_Wakeup_Enable()        REG_W(bFM3_USB0_UDCIE_WKUPIE, 1)
#define FM3_USB0_Wakeup_Clear()         REG_W(bFM3_USB0_UDCS_WKUP, 0)
#define FM3_USB0_Wakeup_Set()           REG_W(bFM3_USB0_UDCS_WKUP, 1)
#define FM3_USB0_EP0_Stall_Clear()      REG_W(bFM3_USB0_EP0C_STAL, 0)
#define FM3_USB0_EP0_Stall_Set()        REG_W(bFM3_USB0_EP0C_STAL, 1)
#define FM3_USB0_EP0_TxInt_Disable()    REG_W(bFM3_USB0_EP0IS_DRQIIE, 0)
#define FM3_USB0_EP0_TxInt_Enable()     REG_W(bFM3_USB0_EP0IS_DRQIIE, 1)
#define FM3_USB0_EP0_RxInt_Disable()    REG_W(bFM3_USB0_EP0OS_DRQOIE, 0)
#define FM3_USB0_EP0_RxInt_Enable()     REG_W(bFM3_USB0_EP0OS_DRQOIE, 1)
#define FM3_USB0_EP0_TxInt_Clear()      REG_W(bFM3_USB0_EP0IS_DRQI, 0);
#define FM3_USB0_EP0_TxInt_Set()        REG_W(bFM3_USB0_EP0IS_DRQI, 1);
#define FM3_USB0_EP0_RxInt_Clear()      REG_W(bFM3_USB0_EP0OS_DRQO, 0);
#define FM3_USB0_EP0_RxInt_Set()        REG_W(bFM3_USB0_EP0OS_DRQO, 1);
#define FM3_USB0_EP0_SPK_Clear()        REG_W(bFM3_USB0_EP0OS_SPK, 0);
#define FM3_USB0_EP0_PSK_Set()          REG_W(bFM3_USB0_EP0OS_SPK, 1);

#endif /* FM3_USB_FUNCTIONS_H_ */
